#pragma once
#include "dijkstra_sh_path.h"
namespace test
{
   struct test_case_context_t
   {
      test_case_context_t(graph::point_pair_t points)
         :  points_(points)
         ,  vertex_not_found_(false)
         ,  etalon_complited_(true)
      {         
         vertex_not_found_ = vertex_not_found_ ||
            !graph::global::get_instance().graph_->get_nearest_vertex(points_.first, ids_.first);
         vertex_not_found_ = vertex_not_found_ ||
            !graph::global::get_instance().graph_->get_nearest_vertex(points_.second, ids_.second);
         if (vertex_not_found_)
         {
            BOOST_TEST_MESSAGE("vertex not found " << 
                               points.first.lat_ << " " <<
                               points.first.lon_ << " " <<
                               points.second.lat_ << " " <<
                               points.second.lon_
                               );
         }
      }
      
      test_case_context_t(graph::vertex_id_pair_t ids)
         :  vertex_not_found_(false)
         ,  ids_(ids)
         ,  etalon_complited_(true)
      {         
         
      }
      
      ~test_case_context_t()
      {}
      
      graph::point_pair_t get_start_finish_points()
      {
         return points_;
      }
      
      graph::vertex_id_pair_t get_start_finish_ids()
      {
         return ids_;
      }
      
      std::list<graph::lat_lon_t> const & get_etalon_sh_path()
      {
         return etalon_path_;
      }
      
      bool get_vertex_not_found() const
      {
         return vertex_not_found_;
      }
      
      bool paths_equals(std::list<graph::lat_lon_t> const & a) const
      {
         if (vertex_not_found_)
            return true; //let's think that if we haven't found neaest vertex - the test case is completed
         if (!etalon_complited_)
         {
            if (!a.empty())
               BOOST_TEST_MESSAGE("this fail was forced cause astar reached the target" 
                  << ids_.first <<" " << ids_.second);
            return a.empty(); //if sh path is not empty - then a is onvalid path
         }
         //strict approach
         if (a.size() != etalon_path_.size())
         {
            BOOST_TEST_MESSAGE("path point counts are not equal " << a.size() << " " << etalon_path_.size());
            BOOST_TEST_MESSAGE("vertex_ids " << ids_.first << " " << ids_.second);
            
            return false;
         }
         std::list<graph::lat_lon_t>::const_iterator it_a = a.begin();
         std::list<graph::lat_lon_t>::const_iterator it_b = etalon_path_.begin();
         for(; it_a != a.end() && it_b != etalon_path_.end(); ++it_a, ++it_b)
         {
            lat_lon_t diff = (*it_a) - (*it_b);
            lat_lon_t max_diff = std::numeric_limits<graph::lat_lon_t>::epsilon();
            if ( diff > max_diff )
            {
               BOOST_TEST_MESSAGE("path points are not equal " << diff << " " << max_diff);
               BOOST_TEST_MESSAGE("vertex_ids " << ids_.first << " " << ids_.second);
               return false;
            }
         }
         return true;
         //non-strict approach
         //lat_lon_t a_len = 0;
         //lat_lon_t etalon_len = 0;
         //std::list<graph::lat_lon_t>::const_iterator it_a = a.begin();
         //std::list<graph::lat_lon_t>::const_iterator a_end = a.end(); ----a_end;
         //std::list<graph::lat_lon_t>::const_iterator it_b = etalon_path_.begin();
         //std::list<graph::lat_lon_t>::const_iterator b_end = etalon_path_.end(); ----b_end;
         ////std::ofstream f1("out1.txt", std::ios_base::trunc);
         ////std::ofstream f2("out2.txt", std::ios_base::trunc);
         //for(; it_a != a_end;)
         //{
         //   point_t temp1;
         //   point_t temp2;
         //   temp1.lat_ = *it_a;
         //   temp1.lon_ = *(++it_a);
         //   //f1 << temp1.lat_ << std::endl;
         //   //f1 << temp1.lon_ << std::endl;
         //   std::list<graph::lat_lon_t>::const_iterator temp_it(++it_a);
         //   temp2.lat_ = *temp_it;
         //   temp2.lon_ = *(++temp_it);
         //   
         //   a_len += math::distance(temp1, temp2);
         //}
         //
         //for(; it_b != b_end;)
         //{
         //   point_t temp1;
         //   point_t temp2;
         //   temp1.lat_ = *it_b;
         //   temp1.lon_ = *(++it_b);
         //   //f2 << temp1.lat_ << std::endl;
         //   //f2 << temp1.lon_ << std::endl;
         //   std::list<graph::lat_lon_t>::const_iterator temp_it(++it_b);
         //   temp2.lat_ = *temp_it;
         //   temp2.lon_ = *(++temp_it);
         //   
         //   etalon_len += math::distance(temp1, temp2);
         //} 
         ////f1.flush();
         ////f2.flush();           
         ////f1.close();
         ////f2.close();
         //if(abs(a_len - etalon_len) > 0.0005f) //0.5 meters diff allowed
         //{
         //   BOOST_TEST_MESSAGE( "sh path len is " << 1000 * etalon_len << " and " << 1000*a_len << " meters " <<
         //      "diff of sh path len is: " << 1000 * (a_len - etalon_len) << " meters");
         //   BOOST_TEST_MESSAGE("vertex_ids " << ids_.first << " " << ids_.second);
         //   return false;
         //}
         //return true; 
      }
      void run()
      {
         if (!vertex_not_found_)
         {
            dijkstra_sh_path_t alg(*graph::global::get_instance().graph_, ids_.first, ids_.second);
            etalon_complited_ = alg.completed_;
            etalon_path_ = alg.sh_path_;
            /*if (!alg.completed_)
            {
               BOOST_TEST_MESSAGE("no path between given vertices " << 
                               ids_.first << " " << ids_.second);
            }*/
         }
      }
   private:
      graph::point_pair_t points_;
      graph::vertex_id_pair_t ids_;
      std::list<graph::lat_lon_t> etalon_path_;
      bool vertex_not_found_;
      bool etalon_complited_;
   };

}